Push Button Device Driver

Block 입력
입력이 공급될 때까지 기다려서, 입력이 공급되면 입력을 반환
인터럽트를 사용한 blocked 입력
버튼이 눌러질 때 까지 wait 상태가 됨
버튼이 눌러지면, interrupt handler가 실행되어 wait 상태인 프로세스를 깨우고 눌려진 버튼 정보를 반환
Push Button Key Parrellel Port
주소: 0xFF200050

Push Button 디바이스 드라이버
key.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("BONITA");
MODULE_DESCRIPTION("DE1SoC PushButton Device Driver");
#define addr_LED 0
#define addr_HEX0 0x20
#define addr_HEX1 0x30
#define addr_SW 0x40
#define addr_KEY 0x50
#define offset_INTMASK 0x08
#define offset_EDGE 0x0c
#define KEY_DEVMAJOR 242
#define KEY_DEVNAME "keys"
static void *mem_base; //basic virtual address of FPGA peripherals
static void *key_addr; //virtual address of KEY Button
static int key_open(struct inode* minode, struct file* mfile){
return 0;
}
static int key_release(struct inoed* minode, struct file* mfile){
return 0;
}
static ssize_t key_write(struct file* file, const char __user *buf, size_t count, loff_t* f_pos){
return 0;
}
static DECLARE_WAIT_QUEUE_HEAD(key_queue);
static int flag=0;
unsigned int key_data;
static ssize_t key_read(struct file* file, char __user* buf, size_t count, loff_t* f_pos){
wait_event_interruptible(key_queue, flag!=0);
flag=0;
put_user(key_data, buf);
return 4;
}
static struct file_operations key_fops={
read= key_read;
write= key_write,
open= key_open,
release= key_release
};
irq_handler_t irq_handler(int irq, void* dev_id, struct pt_regs* regs){
key_data=ioread32(key_addr+offset_EDGE);
flag=1;
wake_up_interruptible(&key_queue);
return (irq_handler_t)IRQ_HANDLED;
}
static int __init keys_init(void){
int res;
res=register_chardev(KEY_DEVMAJOR, KEY_DEVNAME, &key_fops);
if(res<0){
printk(KERN_ERR "push buttons: failed to register device.\n");
return res;
}
mem_base=ioremap_nocache(base_lwFPGA, len_lwFPGA);
if(!mem_base){
printk("Error mapping memory\n");
release_mem_region(base_lwFPGA, len_lwFPGA);
return -EBUSY;
}
key_addr=mem_base+addr_KEY;
//Clear the PID edgecapure register
iowrite32(0xf, key_addr+offset_EDGE);
//Enable IRQ generation for the 4 button
iowrite32(0xf, key_addr+offset_INTMASK);
res=request_irq(73, (irq_handler_t)irq_handler, IRQF_SHARED, "key_irq_handler", (void*)(irq_handler));
if(res){
printk("failed to register key interrupt handler\n");
return res;
}
printk("Device: %s MAJOR: %d\n", KEY_DEVNAME, KEY_DEVMAJOR);
return 0;
}
static void __exit keys_exit(void){
free_irq(73, (void*)irq_handler);
iounmap(mem_base);
unregister_chrdev(KEY_DEVMAJOR, KEY_DEVNAME);
printk("%s unregisterd.\n", KEY_DEVNAME);
}
module_init(keys_init);
moduel_exit(keys_exit);
Makefile
obj-m += key.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clea:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
app_key.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.c>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
int main(void){
int dev, data, rdata;
dev=open("/dev/key", O_RDONLY);
if(dev<0){
fprintf(stderr, "cannot open KEY button device\n");
return 1;
}
read(dev, $rdata, 4);
printf("key data=%x\n", rdata);
return 0;
}
$ make
$ mknod /dev/key c 242 0
$ insmod key.ko
$ lsmod
static int key_use=0;
static int key_open(struct inode* minode, struct file* mfile){
if(test_and_set_bit(0, (void*)&key_use))return -EBUSY;
return 0;
}
static int key_release(struct inode* minode, struct file* mfile){
key_use=0;
return 0;
}